package oidc

import (
	"context"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

var OidcCodeFetcher *BrowserFetcher

type CodeFetcher interface {
	Fetch(a *App) (code string)
}

func NewBrowserFetcher() (c *BrowserFetcher) {
	return &BrowserFetcher{}
}

type BrowserFetcher struct {
	CodeFetcher
}

func (f *BrowserFetcher) Fetch(a *App) (code string) {
	var err error
	waitToken := make(chan struct{})
	srv := http.Server{
		Addr: ":5555",
	}
	go func() {
		if err = srv.ListenAndServe(); err != http.ErrServerClosed {
			logrus.Fatalf("ListenAndServe(): %v", err)
		}
	}()
	_ = OpenBrowser(a.GetLoginUrl())
	http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
		code = r.URL.Query().Get("code")
		go func() {
			_ = srv.Shutdown(context.TODO())
		}()
		js := `<h1>登录成功,请关闭当前窗口</h1>`
		_, _ = w.Write([]byte(js))
		close(waitToken)
	})
	<-waitToken
	return
}

// OpenBrowser opens up the provided URL in a browser
func OpenBrowser(url string) error {
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "openbsd":
		fallthrough
	case "linux":
		cmd = exec.Command("xdg-open", url)
	case "darwin":
		cmd = exec.Command("open", url)
	case "windows":
		r := strings.NewReplacer("&", "^&")
		cmd = exec.Command("cmd", "/c", "start", r.Replace(url))
	}
	if cmd != nil {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err := cmd.Start()
		if err != nil {
			logrus.Infof("Failed to open browser due to error %v", err)
			return fmt.Errorf("Failed to open browser: " + err.Error())
		}
		err = cmd.Wait()
		if err != nil {
			err = fmt.Errorf("Failed to wait for open browser command to finish: " + err.Error())
			logrus.Infof(err.Error())
			return err
		}
		return nil
	} else {
		return errors.New("unsupported platform")
	}
}
